package com.ehi.cuke.common.step;

import com.ehi.cuke.common.BaseStepDefs;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.google.common.io.Resources;
import cucumber.api.java.en.And;
import cucumber.api.java.en.Given;
import cucumber.api.java.en.Then;
import cucumber.api.java.en.When;
import org.json.JSONException;
import org.json.JSONObject;

import javax.ws.rs.client.Entity;
import javax.ws.rs.client.Invocation;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.Form;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.text.ParseException;
import java.util.Map;

import static net.javacrumbs.jsonunit.fluent.JsonFluentAssert.assertThatJson;
import static org.assertj.core.api.Assertions.assertThat;

public class CommonStepDefs extends BaseStepDefs {

    @When("^I send a GET request to \"(.+)\"$")
    public void iSendAGetRequestTo(String uri) throws UnsupportedEncodingException, ParseException {
    	WebTarget target=null;
    	if(uri.contains("ehi/core"))
    		target = restClientService.getWebTarget(chapiUrl + uri);
    	else
        target = restClientService.getWebTarget(apiUrl + uri);

        Invocation.Builder requestBuilder = target.request();

        for (String key : restClientContext.getRequestHeaders().keySet()) {
            String value = restClientContext.getRequestHeader(key);
            requestBuilder.header(key, value);
        }

        for (String key : restClientContext.getCookies().keySet()) {
            String value = restClientContext.getCookies().get(key);
            requestBuilder.cookie(key, value);
        }

        if (!restClientContext.getAuthorizationHeader().isEmpty()) {
            requestBuilder.header("Authorization", restClientContext.getAuthorizationHeader().toString());
        }

        restClientContext.setResponse(requestBuilder.accept(MediaType.APPLICATION_JSON).get());
    }

    @Given("^user (\\d+) has logged in$")
	public void userHasLoggedIn(String userProfileId)
			throws JsonProcessingException, IOException, JSONException {
		WebTarget target = restClientService.getWebTarget(apiUrl
				+ "/auth/authenticated-session");

		Form form = new Form();
		form.param("userProfileId", userProfileId);
		Response response=target
				.request()
				.accept(MediaType.APPLICATION_JSON)
				.post(Entity.entity(form,
						MediaType.APPLICATION_FORM_URLENCODED_TYPE));
		JSONObject JSONresponse = new JSONObject(response.readEntity(String.class));
		String token = JSONresponse.getString("token").toString();
		restClientContext.getAuthorizationHeader().setIstoreToken(token);
		restClientContext.setCookie("istore_token", token);

	}

    @And("user (\\d+) has logged out")
	public void userLoggedOut(String userProfileId) throws JSONException {
		Map<String, String> cookies = restClientContext.getCookies();
		String istoreToken = cookies.get("istore_token");
		WebTarget target = restClientService.getWebTarget(apiUrl
				+ "/auth/authenticated-session/" + istoreToken);

		Form form = new Form();
		form.param("userProfileId", userProfileId);
		Response response = target.request().accept(MediaType.APPLICATION_JSON)
				.delete();
		if (response.getStatus() == 200) {
			System.out.println("Logout success");
		} else {
			throw new IllegalAccessError("Logout failed");
		}
	}

    @When("^I send a POST request to \"(.+)\"$")
    public void iSendAPostRequestTo(String uri,String requestJson) {
    	WebTarget target=null;
    	if(uri.contains("ehi/core"))
    		target = restClientService.getWebTarget(chapiUrl + uri);
    	else
        target = restClientService.getWebTarget(apiUrl + uri);

        Invocation.Builder requestBuilder = target.request();

        for (String key : restClientContext.getRequestHeaders().keySet()) {
            String value = restClientContext.getRequestHeader(key);
            requestBuilder.header(key, value);
        }

        for (String key : restClientContext.getCookies().keySet()) {
            String value = restClientContext.getCookies().get(key);
            requestBuilder.cookie(key, value);
        }

        if (!restClientContext.getAuthorizationHeader().isEmpty()) {
            requestBuilder.header("Authorization", restClientContext.getAuthorizationHeader().toString());
        }

        //Form form = new Form();
        restClientContext.setResponse(requestBuilder.accept(MediaType.APPLICATION_JSON).post(Entity.entity(requestJson, MediaType.APPLICATION_JSON)));
    }

    @When("^I send a raw data \"(.+)\" POST request to \"(.+)\"$")
    public void iSendARawDataPostRequestTo(String filePath, String uri) throws IOException {
    	WebTarget target=null;
    	if(uri.contains("ehi/core"))
    		target = restClientService.getWebTarget(chapiUrl + uri);
    	else
        target = restClientService.getWebTarget(apiUrl + uri);

        Invocation.Builder requestBuilder = target.request();

        for (String key : restClientContext.getRequestHeaders().keySet()) {
            String value = restClientContext.getRequestHeader(key);
            requestBuilder.header(key, value);
        }

        for (String key : restClientContext.getCookies().keySet()) {
            String value = restClientContext.getCookies().get(key);
            requestBuilder.cookie(key, value);
        }

        if (!restClientContext.getAuthorizationHeader().isEmpty()) {
            requestBuilder.header("Authorization", restClientContext.getAuthorizationHeader().toString());
        }

        Response response = requestBuilder.accept(MediaType.APPLICATION_JSON).post(
                Entity.entity(Resources.toString(Resources.getResource(filePath), Charset.forName("UTF-8")), MediaType.APPLICATION_JSON));
        restClientContext.setResponse(response);
    }

    @Then("^the response status should be (\\d+)$")
    public void theResponseStatusShouldBe(int statusCode) {
        assertThat(restClientContext.getResponse().getStatus()).isEqualTo(statusCode);
    }

    @And("^the JSON response should be$")
    public void theJsonResponseShouldBe(String json) {
        assertThatJson(restClientContext.getResponseJson()).isEqualTo(json);
    }

    @And("^the error message should be \"(.+)\"$")
    public void theErrorMessageIs(String message) {
        assertThatJson(restClientContext.getResponseJson()).node("error.message").isEqualTo(message);
    }

    @And("^the error message contains \"(.+)\"$")
    public void theErrorMessageContains(String message) throws JSONException {
        JSONObject response = new JSONObject(restClientContext.getResponseJson());
        assertThat(response.getJSONObject("error").getString("message")).contains(message);
    }

    @And("^the error type should be \"(.+)\"$")
    public void theErrorTypeIs(String type) {
        assertThatJson(restClientContext.getResponseJson()).node("error.type").isEqualTo(type);
    }

    @And("^the JSON response should contain key:value \"(.+)\":\"(.+)\"$")
    public void theJsonResponseShouldContainKeyAndValue(String key, String value) {
       assertThatJson(restClientContext.getResponseJson()).node(key).isEqualTo("\""+value+"\"");
    }
}
